/*
 *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "rtp/webrtc/rtp_utility.h"

#include <assert.h>
#include <math.h>  // ceil
#include <string.h>  // memcpy

#if defined(_WIN32)
// Order for these headers are important
#include <Windows.h>  // FILETIME

#include <WinSock.h>  // timeval

#include <MMSystem.h>  // timeGetTime
#elif((defined WEBRTC_LINUX) || (defined WEBRTC_MAC))
#include <sys/time.h>  // gettimeofday
#include <time.h>
#endif
#if (defined(_DEBUG) && defined(_WIN32) && (_MSC_VER >= 1400))
#include <stdio.h>
#endif

// #include "webrtc/system_wrappers/interface/tick_util.h"
// #include "webrtc/system_wrappers/interface/logging.h"

// #if (defined(_DEBUG) && defined(_WIN32) && (_MSC_VER >= 1400))
// #define DEBUG_PRINT(...)           \
//   {                                \
//     char msg[256];                 \
//     sprintf(msg, __VA_ARGS__);     \  // NOLINT
//     OutputDebugString(msg);        \
//   }
// #else
// special fix for visual 2003
#define DEBUG_PRINT(exp)        ((void)0)
//#endif  // defined(_DEBUG) && defined(_WIN32)


// Processor architecture detection.  For more info on what's defined, see:
//   http://msdn.microsoft.com/en-us/library/b0084kay.aspx
//   http://www.agner.org/optimize/calling_conventions.pdf
//   or with gcc, run: "echo | gcc -E -dM -"
#if defined(_M_X64) || defined(__x86_64__)
#define WEBRTC_ARCH_X86_FAMILY
#define WEBRTC_ARCH_X86_64
#define WEBRTC_ARCH_64_BITS
#define WEBRTC_ARCH_LITTLE_ENDIAN
#elif defined(__aarch64__)
#define WEBRTC_ARCH_64_BITS
#define WEBRTC_ARCH_LITTLE_ENDIAN
#elif defined(_M_IX86) || defined(__i386__)
#define WEBRTC_ARCH_X86_FAMILY
#define WEBRTC_ARCH_X86
#define WEBRTC_ARCH_32_BITS
#define WEBRTC_ARCH_LITTLE_ENDIAN
#elif defined(__ARMEL__)
// TODO(ajm): We'd prefer to control platform defines here, but this is
// currently provided by the Android makefiles. Commented to avoid duplicate
// definition warnings.
// #define WEBRTC_ARCH_ARM
// TODO(ajm): Chromium uses the following two defines. Should we switch?
// #define WEBRTC_ARCH_ARM_FAMILY
// #define WEBRTC_ARCH_ARMEL
#define WEBRTC_ARCH_32_BITS
#define WEBRTC_ARCH_LITTLE_ENDIAN
#elif defined(__MIPSEL__)
#define WEBRTC_ARCH_32_BITS
#define WEBRTC_ARCH_LITTLE_ENDIAN
#elif defined(__pnacl__)
#define WEBRTC_ARCH_32_BITS
#define WEBRTC_ARCH_LITTLE_ENDIAN
#else
#error Please add support for your architecture in typedefs.h
#endif

#if defined(WEBRTC_ARCH_LITTLE_ENDIAN)
#pragma message "LITTLE ENDIAN DEFINED"
#endif

#if !(defined(WEBRTC_ARCH_LITTLE_ENDIAN) ^ defined(WEBRTC_ARCH_BIG_ENDIAN))
#error Define either WEBRTC_ARCH_LITTLE_ENDIAN or WEBRTC_ARCH_BIG_ENDIAN
#endif

#if (defined(WEBRTC_ARCH_X86_FAMILY) && !defined(__SSE2__)) ||  \
    (defined(WEBRTC_ARCH_ARM_V7) && !defined(WEBRTC_ARCH_ARM_NEON))
#define WEBRTC_CPU_DETECTION
#endif

namespace webrtc {

// RtpData* NullObjectRtpData() {
//  static NullRtpData null_rtp_data;
//  return &null_rtp_data;
// }

// RtpFeedback* NullObjectRtpFeedback() {
//  static NullRtpFeedback null_rtp_feedback;
//  return &null_rtp_feedback;
// }

// RtpAudioFeedback* NullObjectRtpAudioFeedback() {
//  static NullRtpAudioFeedback null_rtp_audio_feedback;
//  return &null_rtp_audio_feedback;
// }

// ReceiveStatistics* NullObjectReceiveStatistics() {
//  static NullReceiveStatistics null_receive_statistics;
//  return &null_receive_statistics;
// }

namespace RtpUtility {

enum {
  kRtcpExpectedVersion = 2,
  kRtcpMinHeaderLength = 4,
  kRtcpMinParseLength = 8,

  kRtpExpectedVersion = 2,
  kRtpMinParseLength = 12
};

/*
 * Time routines.
 */

// uint32_t GetCurrentRTP(Clock* clock, uint32_t freq) {
//  const bool use_global_clock = (clock == NULL);
//  Clock* local_clock = clock;
//  if (use_global_clock) {
//    local_clock = Clock::GetRealTimeClock();
//  }
//  uint32_t secs = 0, frac = 0;
//  local_clock->CurrentNtp(secs, frac);
//  if (use_global_clock) {
//    delete local_clock;
//  }
//  return ConvertNTPTimeToRTP(secs, frac, freq);
// }

// uint32_t ConvertNTPTimeToRTP(uint32_t NTPsec, uint32_t NTPfrac, uint32_t freq) {
//  float ftemp = (float)NTPfrac / (float)NTP_FRAC;
//  uint32_t tmp = (uint32_t)(ftemp * freq);
//  return NTPsec * freq + tmp;
// }

// uint32_t ConvertNTPTimeToMS(uint32_t NTPsec, uint32_t NTPfrac) {
//  int freq = 1000;
//  float ftemp = (float)NTPfrac / (float)NTP_FRAC;
//  uint32_t tmp = (uint32_t)(ftemp * freq);
//  uint32_t MStime = NTPsec * freq + tmp;
//  return MStime;
// }

/*
 * Misc utility routines
 */

#if defined(_WIN32)
bool StringCompare(const char* str1, const char* str2,
                   const uint32_t length) {
  return (_strnicmp(str1, str2, length) == 0) ? true : false;
}
#elif defined(WEBRTC_LINUX) || defined(WEBRTC_MAC)
bool StringCompare(const char* str1, const char* str2,
                   const uint32_t length) {
  return (strncasecmp(str1, str2, length) == 0) ? true : false;
}
#endif

/* for RTP/RTCP
    All integer fields are carried in network byte order, that is, most
    significant byte (octet) first.  AKA big-endian.
*/
void AssignUWord32ToBuffer(uint8_t* dataBuffer, uint32_t value) {
#if defined(WEBRTC_ARCH_LITTLE_ENDIAN)
  dataBuffer[0] = static_cast<uint8_t>(value >> 24);
  dataBuffer[1] = static_cast<uint8_t>(value >> 16);
  dataBuffer[2] = static_cast<uint8_t>(value >> 8);
  dataBuffer[3] = static_cast<uint8_t>(value);
#else
  uint32_t* ptr = reinterpret_cast<uint32_t*>(dataBuffer);
  ptr[0] = value;
#endif
}

void AssignUWord24ToBuffer(uint8_t* dataBuffer, uint32_t value) {
#if defined(WEBRTC_ARCH_LITTLE_ENDIAN)
  dataBuffer[0] = static_cast<uint8_t>(value >> 16);
  dataBuffer[1] = static_cast<uint8_t>(value >> 8);
  dataBuffer[2] = static_cast<uint8_t>(value);
#else
  dataBuffer[0] = static_cast<uint8_t>(value);
  dataBuffer[1] = static_cast<uint8_t>(value >> 8);
  dataBuffer[2] = static_cast<uint8_t>(value >> 16);
#endif
}

void AssignUWord16ToBuffer(uint8_t* dataBuffer, uint16_t value) {
#if defined(WEBRTC_ARCH_LITTLE_ENDIAN)
  dataBuffer[0] = static_cast<uint8_t>(value >> 8);
  dataBuffer[1] = static_cast<uint8_t>(value);
#else
  uint16_t* ptr = reinterpret_cast<uint16_t*>(dataBuffer);
  ptr[0] = value;
#endif
}

uint16_t BufferToUWord16(const uint8_t* dataBuffer) {
#if defined(WEBRTC_ARCH_LITTLE_ENDIAN)
  return (dataBuffer[0] << 8) + dataBuffer[1];
#else
  return *reinterpret_cast<const uint16_t*>(dataBuffer);
#endif
}

uint32_t BufferToUWord24(const uint8_t* dataBuffer) {
  return (dataBuffer[0] << 16) + (dataBuffer[1] << 8) + dataBuffer[2];
}

uint32_t BufferToUWord32(const uint8_t* dataBuffer) {
#if defined(WEBRTC_ARCH_LITTLE_ENDIAN)
  return (dataBuffer[0] << 24) + (dataBuffer[1] << 16) + (dataBuffer[2] << 8) +
      dataBuffer[3];
#else
  return *reinterpret_cast<const uint32_t*>(dataBuffer);
#endif
}

uint32_t pow2(uint8_t exp) {
  return 1 << exp;
}

// void RTPPayload::SetType(RtpVideoCodecTypes videoType) {
//  type = videoType;

//  switch (type) {
//    case kRtpVideoGeneric:
//      break;
//    case kRtpVideoVp8: {
//      info.VP8.nonReferenceFrame = false;
//      info.VP8.beginningOfPartition = false;
//      info.VP8.partitionID = 0;
//      info.VP8.hasPictureID = false;
//      info.VP8.hasTl0PicIdx = false;
//      info.VP8.hasTID = false;
//      info.VP8.hasKeyIdx = false;
//      info.VP8.pictureID = -1;
//      info.VP8.tl0PicIdx = -1;
//      info.VP8.tID = -1;
//      info.VP8.layerSync = false;
//      info.VP8.frameWidth = 0;
//      info.VP8.frameHeight = 0;
//      break;
//    }
//    default:
//      break;
//  }
// }

// RtpHeaderParser::RtpHeaderParser(const uint8_t* rtpData,
//                                 const size_t rtpDataLength)
//    : _ptrRTPDataBegin(rtpData),
//      _ptrRTPDataEnd(rtpData ? (rtpData + rtpDataLength) : NULL) {
// }

// RtpHeaderParser::~RtpHeaderParser() {
// }

// bool RtpHeaderParser::RTCP() const {
//  // 72 to 76 is reserved for RTP
//  // 77 to 79 is not reserver but  they are not assigned we will block them
//  // for RTCP 200 SR  == marker bit + 72
//  // for RTCP 204 APP == marker bit + 76
//  /*
//  *       RTCP
//  *
//  * FIR      full INTRA-frame request             192     [RFC2032]   supported
//  * NACK     negative acknowledgement             193     [RFC2032]
//  * IJ       Extended inter-arrival jitter report 195     [RFC-ietf-avt-rtp-toff
//  * set-07.txt] http:// tools.ietf.org/html/draft-ietf-avt-rtp-toffset-07
//  * SR       sender report                        200     [RFC3551]   supported
//  * RR       receiver report                      201     [RFC3551]   supported
//  * SDES     source description                   202     [RFC3551]   supported
//  * BYE      goodbye                              203     [RFC3551]   supported
//  * APP      application-defined                  204     [RFC3551]   ignored
//  * RTPFB    Transport layer FB message           205     [RFC4585]   supported
//  * PSFB     Payload-specific FB message          206     [RFC4585]   supported
//  * XR       extended report                      207     [RFC3611]   supported
//  */

//  /* 205       RFC 5104
//   * FMT 1      NACK       supported
//   * FMT 2      reserved
//   * FMT 3      TMMBR      supported
//   * FMT 4      TMMBN      supported
//   */

//  /* 206      RFC 5104
//  * FMT 1:     Picture Loss Indication (PLI)                      supported
//  * FMT 2:     Slice Lost Indication (SLI)
//  * FMT 3:     Reference Picture Selection Indication (RPSI)
//  * FMT 4:     Full Intra Request (FIR) Command                   supported
//  * FMT 5:     Temporal-Spatial Trade-off Request (TSTR)
//  * FMT 6:     Temporal-Spatial Trade-off Notification (TSTN)
//  * FMT 7:     Video Back Channel Message (VBCM)
//  * FMT 15:    Application layer FB message
//  */

//  const ptrdiff_t length = _ptrRTPDataEnd - _ptrRTPDataBegin;
//  if (length < kRtcpMinHeaderLength) {
//    return false;
//  }

//  const uint8_t V  = _ptrRTPDataBegin[0] >> 6;
//  if (V != kRtcpExpectedVersion) {
//    return false;
//  }

//  const uint8_t  payloadType = _ptrRTPDataBegin[1];
//  bool RTCP = false;
//  switch (payloadType) {
//    case 192:
//      RTCP = true;
//      break;
//    case 193:
//      // not supported
//      // pass through and check for a potential RTP packet
//      break;
//    case 195:
//    case 200:
//    case 201:
//    case 202:
//    case 203:
//    case 204:
//    case 205:
//    case 206:
//    case 207:
//      RTCP = true;
//      break;
//  }
//  return RTCP;
// }

// bool RtpHeaderParser::ParseRtcp(RTPHeader* header) const {
//  assert(header != NULL);

//  const ptrdiff_t length = _ptrRTPDataEnd - _ptrRTPDataBegin;
//  if (length < kRtcpMinParseLength) {
//    return false;
//  }

//  const uint8_t V = _ptrRTPDataBegin[0] >> 6;
//  if (V != kRtcpExpectedVersion) {
//    return false;
//  }

//  const uint8_t PT = _ptrRTPDataBegin[1];
//  const uint16_t len = (_ptrRTPDataBegin[2] << 8) + _ptrRTPDataBegin[3];
//  const uint8_t* ptr = &_ptrRTPDataBegin[4];

//  uint32_t SSRC = *ptr++ << 24;
//  SSRC += *ptr++ << 16;
//  SSRC += *ptr++ << 8;
//  SSRC += *ptr++;

//  header->payloadType  = PT;
//  header->ssrc         = SSRC;
//  header->headerLength = 4 + (len << 2);

//  return true;
// }

// bool RtpHeaderParser::Parse(RTPHeader& header,
//                            RtpHeaderExtensionMap* ptrExtensionMap) const {
//  const ptrdiff_t length = _ptrRTPDataEnd - _ptrRTPDataBegin;
//  if (length < kRtpMinParseLength) {
//    return false;
//  }

//  // Version
//  const uint8_t V  = _ptrRTPDataBegin[0] >> 6;
//  // Padding
//  const bool          P  = ((_ptrRTPDataBegin[0] & 0x20) == 0) ? false : true;
//  // eXtension
//  const bool          X  = ((_ptrRTPDataBegin[0] & 0x10) == 0) ? false : true;
//  const uint8_t CC = _ptrRTPDataBegin[0] & 0x0f;
//  const bool          M  = ((_ptrRTPDataBegin[1] & 0x80) == 0) ? false : true;

//  const uint8_t PT = _ptrRTPDataBegin[1] & 0x7f;

//  const uint16_t sequenceNumber = (_ptrRTPDataBegin[2] << 8) +
//      _ptrRTPDataBegin[3];

//  const uint8_t* ptr = &_ptrRTPDataBegin[4];

//  uint32_t RTPTimestamp = *ptr++ << 24;
//  RTPTimestamp += *ptr++ << 16;
//  RTPTimestamp += *ptr++ << 8;
//  RTPTimestamp += *ptr++;

//  uint32_t SSRC = *ptr++ << 24;
//  SSRC += *ptr++ << 16;
//  SSRC += *ptr++ << 8;
//  SSRC += *ptr++;

//  if (V != kRtpExpectedVersion) {
//    return false;
//  }

//  const uint8_t CSRCocts = CC * 4;

//  if ((ptr + CSRCocts) > _ptrRTPDataEnd) {
//    return false;
//  }

//  header.markerBit      = M;
//  header.payloadType    = PT;
//  header.sequenceNumber = sequenceNumber;
//  header.timestamp      = RTPTimestamp;
//  header.ssrc           = SSRC;
//  header.numCSRCs       = CC;
//  header.paddingLength  = P ? *(_ptrRTPDataEnd - 1) : 0;

//  for (unsigned int i = 0; i < CC; ++i) {
//    uint32_t CSRC = *ptr++ << 24;
//    CSRC += *ptr++ << 16;
//    CSRC += *ptr++ << 8;
//    CSRC += *ptr++;
//    header.arrOfCSRCs[i] = CSRC;
//  }

//  header.headerLength   = 12 + CSRCocts;

//  // If in effect, MAY be omitted for those packets for which the offset
//  // is zero.
//  header.extension.hasTransmissionTimeOffset = false;
//  header.extension.transmissionTimeOffset = 0;

//  // May not be present in packet.
//  header.extension.hasAbsoluteSendTime = false;
//  header.extension.absoluteSendTime = 0;

//  // May not be present in packet.
//  header.extension.hasAudioLevel = false;
//  header.extension.audioLevel = 0;

//  if (X) {
//    /* RTP header extension, RFC 3550.
//     0                   1                   2                   3
//     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//    |      defined by profile       |           length              |
//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//    |                        header extension                       |
//    |                             ....                              |
//    */
//    const ptrdiff_t remain = _ptrRTPDataEnd - ptr;
//    if (remain < 4) {
//      return false;
//    }

//    header.headerLength += 4;

//    uint16_t definedByProfile = *ptr++ << 8;
//    definedByProfile += *ptr++;

//    uint16_t XLen = *ptr++ << 8;
//    XLen += *ptr++;  // in 32 bit words
//    XLen *= 4;  // in octs

//    if (remain < (4 + XLen)) {
//      return false;
//    }
//    if (definedByProfile == kRtpOneByteHeaderExtensionId) {
//      const uint8_t* ptrRTPDataExtensionEnd = ptr + XLen;
//      ParseOneByteExtensionHeader(header,
//                                  ptrExtensionMap,
//                                  ptrRTPDataExtensionEnd,
//                                  ptr);
//    }
//    header.headerLength += XLen;
//  }
//  return true;
// }

// void RtpHeaderParser::ParseOneByteExtensionHeader(
//    RTPHeader& header,
//    const RtpHeaderExtensionMap* ptrExtensionMap,
//    const uint8_t* ptrRTPDataExtensionEnd,
//    const uint8_t* ptr) const {
//  if (!ptrExtensionMap) {
//    return;
//  }

//  while (ptrRTPDataExtensionEnd - ptr > 0) {
//    //  0
//    //  0 1 2 3 4 5 6 7
//    // +-+-+-+-+-+-+-+-+
//    // |  ID   |  len  |
//    // +-+-+-+-+-+-+-+-+

//    // Note that 'len' is the header extension element length, which is the
//    // number of bytes - 1.
//    const uint8_t id = (*ptr & 0xf0) >> 4;
//    const uint8_t len = (*ptr & 0x0f);
//    ptr++;

//    if (id == 15) {
//      LOG(LS_WARNING)
//          << "RTP extension header 15 encountered. Terminate parsing.";
//      return;
//    }

//    RTPExtensionType type;
//    if (ptrExtensionMap->GetType(id, &type) != 0) {
//      // If we encounter an unknown extension, just skip over it.
//      LOG(LS_WARNING) << "Failed to find extension id: "
//                      << static_cast<int>(id);
//    } else {
//      switch (type) {
//        case kRtpExtensionTransmissionTimeOffset: {
//          if (len != 2) {
//            LOG(LS_WARNING) << "Incorrect transmission time offset len: "
//                            << len;
//            return;
//          }
//          //  0                   1                   2                   3
//          //  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
//          // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//          // |  ID   | len=2 |              transmission offset              |
//          // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

//          int32_t transmissionTimeOffset = ptr[0] << 16;
//          transmissionTimeOffset += ptr[1] << 8;
//          transmissionTimeOffset += ptr[2];
//          header.extension.transmissionTimeOffset =
//              transmissionTimeOffset;
//          if (transmissionTimeOffset & 0x800000) {
//            // Negative offset, correct sign for Word24 to Word32.
//            header.extension.transmissionTimeOffset |= 0xFF000000;
//          }
//          header.extension.hasTransmissionTimeOffset = true;
//          break;
//        }
//        case kRtpExtensionAudioLevel: {
//          if (len != 0) {
//            LOG(LS_WARNING) << "Incorrect audio level len: " << len;
//            return;
//          }
//          //  0                   1                   2                   3
//          //  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
//          // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//          // |  ID   | len=0 |V|   level     |      0x00     |      0x00     |
//          // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//          //

//          // Parse out the fields but only use it for debugging for now.
//          // const uint8_t V = (*ptr & 0x80) >> 7;
//          // const uint8_t level = (*ptr & 0x7f);
//          // DEBUG_PRINT("RTP_AUDIO_LEVEL_UNIQUE_ID: ID=%u, len=%u, V=%u,
//          // level=%u", ID, len, V, level);

//          header.extension.audioLevel = ptr[0];
//          header.extension.hasAudioLevel = true;
//          break;
//        }
//        case kRtpExtensionAbsoluteSendTime: {
//          if (len != 2) {
//            LOG(LS_WARNING) << "Incorrect absolute send time len: " << len;
//            return;
//          }
//          //  0                   1                   2                   3
//          //  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
//          // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//          // |  ID   | len=2 |              absolute send time               |
//          // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

//          uint32_t absoluteSendTime = ptr[0] << 16;
//          absoluteSendTime += ptr[1] << 8;
//          absoluteSendTime += ptr[2];
//          header.extension.absoluteSendTime = absoluteSendTime;
//          header.extension.hasAbsoluteSendTime = true;
//          break;
//        }
//        default: {
//          LOG(LS_WARNING) << "Extension type not implemented: " << type;
//          return;
//        }
//      }
//    }
//    ptr += (len + 1);
//    uint8_t num_bytes = ParsePaddingBytes(ptrRTPDataExtensionEnd, ptr);
//    ptr += num_bytes;
//  }
// }

// uint8_t RtpHeaderParser::ParsePaddingBytes(
//    const uint8_t* ptrRTPDataExtensionEnd,
//    const uint8_t* ptr) const {
//  uint8_t num_zero_bytes = 0;
//  while (ptrRTPDataExtensionEnd - ptr > 0) {
//    if (*ptr != 0) {
//      return num_zero_bytes;
//    }
//    ptr++;
//    num_zero_bytes++;
//  }
//  return num_zero_bytes;
// }

// RTPPayloadParser::RTPPayloadParser(const RtpVideoCodecTypes videoType,
//                                   const uint8_t* payloadData,
//                                   uint16_t payloadDataLength)
//    : _dataPtr(payloadData),
//      _dataLength(payloadDataLength),
//      _videoType(videoType) {}

// RTPPayloadParser::~RTPPayloadParser() {
// }

// bool RTPPayloadParser::Parse(RTPPayload& parsedPacket) const {
//  parsedPacket.SetType(_videoType);

//  switch (_videoType) {
//    case kRtpVideoGeneric:
//      return ParseGeneric(parsedPacket);
//    case kRtpVideoVp8:
//      return ParseVP8(parsedPacket);
//    default:
//      return false;
//  }
// }

// bool RTPPayloadParser::ParseGeneric(RTPPayload& /*parsedPacket*/) const {
//  return false;
// }

// //
// // VP8 format:
// //
// // Payload descriptor
// //       0 1 2 3 4 5 6 7
// //      +-+-+-+-+-+-+-+-+
// //      |X|R|N|S|PartID | (REQUIRED)
// //      +-+-+-+-+-+-+-+-+
// // X:   |I|L|T|K|  RSV  | (OPTIONAL)
// //      +-+-+-+-+-+-+-+-+
// // I:   |   PictureID   | (OPTIONAL)
// //      +-+-+-+-+-+-+-+-+
// // L:   |   TL0PICIDX   | (OPTIONAL)
// //      +-+-+-+-+-+-+-+-+
// // T/K: |TID:Y| KEYIDX  | (OPTIONAL)
// //      +-+-+-+-+-+-+-+-+
// //
// // Payload header (considered part of the actual payload, sent to decoder)
// //       0 1 2 3 4 5 6 7
// //      +-+-+-+-+-+-+-+-+
// //      |Size0|H| VER |P|
// //      +-+-+-+-+-+-+-+-+
// //      |      ...      |
// //      +               +

// bool RTPPayloadParser::ParseVP8(RTPPayload& parsedPacket) const {
//  RTPPayloadVP8* vp8 = &parsedPacket.info.VP8;
//  const uint8_t* dataPtr = _dataPtr;
//  int dataLength = _dataLength;

//  // Parse mandatory first byte of payload descriptor
//  bool extension = (*dataPtr & 0x80) ? true : false;            // X bit
//  vp8->nonReferenceFrame = (*dataPtr & 0x20) ? true : false;    // N bit
//  vp8->beginningOfPartition = (*dataPtr & 0x10) ? true : false;  // S bit
//  vp8->partitionID = (*dataPtr & 0x0F);          // PartID field

//  if (vp8->partitionID > 8) {
//    // Weak check for corrupt data: PartID MUST NOT be larger than 8.
//    return false;
//  }

//  // Advance dataPtr and decrease remaining payload size
//  dataPtr++;
//  dataLength--;

//  if (extension) {
//    const int parsedBytes = ParseVP8Extension(vp8, dataPtr, dataLength);
//    if (parsedBytes < 0) return false;
//    dataPtr += parsedBytes;
//    dataLength -= parsedBytes;
//  }

//  if (dataLength <= 0) {
//    LOG(LS_ERROR) << "Error parsing VP8 payload descriptor!";
//    return false;
//  }

//  // Read P bit from payload header (only at beginning of first partition)
//  if (dataLength > 0 && vp8->beginningOfPartition && vp8->partitionID == 0) {
//    parsedPacket.frameType = (*dataPtr & 0x01) ? kPFrame : kIFrame;
//  } else {
//    parsedPacket.frameType = kPFrame;
//  }
//  if (0 != ParseVP8FrameSize(parsedPacket, dataPtr, dataLength)) {
//    return false;
//  }
//  parsedPacket.info.VP8.data       = dataPtr;
//  parsedPacket.info.VP8.dataLength = dataLength;
//  return true;
// }

// int RTPPayloadParser::ParseVP8FrameSize(RTPPayload& parsedPacket,
//                                        const uint8_t* dataPtr,
//                                        int dataLength) const {
//  if (parsedPacket.frameType != kIFrame) {
//    // Included in payload header for I-frames.
//    return 0;
//  }
//  if (dataLength < 10) {
//    // For an I-frame we should always have the uncompressed VP8 header
//    // in the beginning of the partition.
//    return -1;
//  }
//  RTPPayloadVP8* vp8 = &parsedPacket.info.VP8;
//  vp8->frameWidth = ((dataPtr[7] << 8) + dataPtr[6]) & 0x3FFF;
//  vp8->frameHeight = ((dataPtr[9] << 8) + dataPtr[8]) & 0x3FFF;
//  return 0;
// }

// int RTPPayloadParser::ParseVP8Extension(RTPPayloadVP8* vp8,
//                                        const uint8_t* dataPtr,
//                                        int dataLength) const {
//  int parsedBytes = 0;
//  if (dataLength <= 0) return -1;
//  // Optional X field is present
//  vp8->hasPictureID = (*dataPtr & 0x80) ? true : false;  // I bit
//  vp8->hasTl0PicIdx = (*dataPtr & 0x40) ? true : false;  // L bit
//  vp8->hasTID = (*dataPtr & 0x20) ? true : false;       // T bit
//  vp8->hasKeyIdx = (*dataPtr & 0x10) ? true : false;    // K bit

//  // Advance dataPtr and decrease remaining payload size
//  dataPtr++;
//  parsedBytes++;
//  dataLength--;

//  if (vp8->hasPictureID) {
//    if (ParseVP8PictureID(vp8, &dataPtr, &dataLength, &parsedBytes) != 0) {
//      return -1;
//    }
//  }

//  if (vp8->hasTl0PicIdx) {
//    if (ParseVP8Tl0PicIdx(vp8, &dataPtr, &dataLength, &parsedBytes) != 0) {
//      return -1;
//    }
//  }

//  if (vp8->hasTID || vp8->hasKeyIdx) {
//    if (ParseVP8TIDAndKeyIdx(vp8, &dataPtr, &dataLength, &parsedBytes) != 0) {
//      return -1;
//    }
//  }
//  return parsedBytes;
// }

// int RTPPayloadParser::ParseVP8PictureID(RTPPayloadVP8* vp8,
//                                        const uint8_t** dataPtr,
//                                        int* dataLength,
//                                        int* parsedBytes) const {
//  if (*dataLength <= 0) return -1;
//  vp8->pictureID = (**dataPtr & 0x7F);
//  if (**dataPtr & 0x80) {
//    (*dataPtr)++;
//    (*parsedBytes)++;
//    if (--(*dataLength) <= 0) return -1;
//    // PictureID is 15 bits
//    vp8->pictureID = (vp8->pictureID << 8) +** dataPtr;
//  }
//  (*dataPtr)++;
//  (*parsedBytes)++;
//  (*dataLength)--;
//  return 0;
// }

// int RTPPayloadParser::ParseVP8Tl0PicIdx(RTPPayloadVP8* vp8,
//                                        const uint8_t** dataPtr,
//                                        int* dataLength,
//                                        int* parsedBytes) const {
//  if (*dataLength <= 0) return -1;
//  vp8->tl0PicIdx = **dataPtr;
//  (*dataPtr)++;
//  (*parsedBytes)++;
//  (*dataLength)--;
//  return 0;
// }

// int RTPPayloadParser::ParseVP8TIDAndKeyIdx(RTPPayloadVP8* vp8,
//                                           const uint8_t** dataPtr,
//                                           int* dataLength,
//                                           int* parsedBytes) const {
//  if (*dataLength <= 0) return -1;
//  if (vp8->hasTID) {
//    vp8->tID = ((**dataPtr >> 6) & 0x03);
//    vp8->layerSync = (**dataPtr & 0x20) ? true : false;  // Y bit
//  }
//  if (vp8->hasKeyIdx) {
//    vp8->keyIdx = (**dataPtr & 0x1F);
//  }
//  (*dataPtr)++;
//  (*parsedBytes)++;
//  (*dataLength)--;
//  return 0;
// }

}  // namespace RtpUtility

}  // namespace webrtc
